﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XW.Logging;
using XW.Data;
using System.Data.SqlClient; 
using System.Configuration;
using System.Data;
using XW.Utils;
using StackExchange.Exceptional;
namespace XW.Core
{

    public  class Db
    {
        public static IDbProvider Provider(string providerName)
        {
            var providers = new Dictionary<string, IDbProvider>(){
                {"DB2",new DB2Provider()},
                {"MySql",new MySqlProvider()},
                {"Oracle",new OracleProvider()},
                {"PostgreSql",new PostgreSqlProvider()},
                {"SqlAzure",new SqlAzureProvider()},
                {"Sqlite",new SqliteProvider()},
                {"SqlServerCompact",new SqlServerCompactProvider()},
                {"SqlServer",new SqlServerProvider()}
            };
            return providers.ContainsKey(providerName) ? providers[providerName] : new SqlServerProvider();
        } 
        public static IDbContext Context()
        {
            return ContextName(App.DB_DEFAULT_CONN_NAME);
        }

        public static IDbContext Context(string connectionString, IDbProvider provider)
        {
            var Log = LogProvider.GetLogger(connectionString); 
            var db = new DbContext().ConnectionString(connectionString, provider);

            db.OnExecuting(x =>
            {
                if (App.OnDbExecuting != null) App.OnDbExecuting(x);
                var sql = x.Command.CommandText;
                for (int i = x.Command.Parameters.Count - 1; i >= 0; i--)
                {
                    var item = x.Command.Parameters[i] as IDataParameter;
                    sql = sql.Replace(item.ParameterName, String.Format("'{0}'", item.Value));
                }
                Log.Debug(sql);
            });

            db.OnError(e =>
            {
                string body = "";
                try
                {
                    body = CommonHelper.GetBody();
                }
                catch (Exception ee)
                {
                     
                }
                
                var ex = e.Exception as SqlException;
                e.Exception?.Log( SXHttpContext.Current, customData: new Dictionary<string, string> { { "body", body }, { "CommandText", e.Command.CommandText } });
                Log.Error(e.Exception, "错误内容:{0};sql:{1}", e.Exception.Message, e.Command.CommandText);
                if (ex != null)
                {
                    var error = "";
                    switch (ex.Number)
                    {
                        case -2:
                            error = "超时时间已到。在操作完成之前超时时间已过或服务器未响应";
                            break;
                        case 4060:
                            // Invalid Database
                            error = "数据库不可用,请检查系统设置后重试！";
                            break;
                        case 18456:
                            // Login Failed
                            error = "登陆数据库失败！";
                            break;
                        case 547:
                            // ForeignKey Violation
                            error = "数据已经被引用，更新失败，请先删除引用数据并重试！";
                            break;
                        case 2627:
                            // Unique Index/Constriant Violation
                            error = "主键重复，更新失败！";
                            break;
                        case 2601:
                            // Unique Index/Constriant Violation   
                            break;
                        default:
                            // throw a general DAL Exception   
                            break;
                    }
                    if (!string.IsNullOrEmpty(error))
                        throw new Exception(error);
                }
            });

            return db;
        }
        public static IDbContext Context(string connString)
        {  
            var db = Context(connString, new SqlServerProvider());
            return db;
        }
        public static IDbContext ContextName(string ConnName)
        { 
            var conn = ConfigHelper.GetConn(ConnName);
            var db = Context(conn, new SqlServerProvider());
            return db;
        }
        public static IDbContext ContextForWebConfig(string ConnName)
        { 
            var setting = ConfigurationManager.ConnectionStrings[ConnName];
            var db = Context(setting.ConnectionString, Provider(setting.ProviderName)); 
            return db;
        }
    }
}
